/* Hey Emacs this is -*- C -*- */

/* GNUPLOT - pstricks.trm */

/*[
 * Copyright 1990 - 1993, 1998, 2004, 2018
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the complete modified source code.  Modifications are to
 * be distributed as patches to the released version.  Permission to
 * distribute binaries produced by compiling modified sources is granted,
 * provided you
 *   1. distribute the corresponding source modifications from the
 *    released version in the form of a patch file along with the binaries,
 *   2. add special version identification to distinguish your version
 *    in addition to the base release version number,
 *   3. provide your name and address as the primary contact for the
 *    support of your modified version, and
 *   4. retain our contact information in regard to use of the base
 *    software.
 * Permission to distribute the released version of the source code along
 * with corresponding source modifications in the form of a patch file is
 * granted with same provisions 2 through 4 for binary distributions.
 *
 * This software is provided "as is" without express or implied warranty
 * to the extent permitted by applicable law.
]*/

/*
 * This file is included by ../term.c.
 *
 * This terminal driver supports:
 *   The PSTricks macros for LaTeX.
 *
 * AUTHORS
 *   David Kotz
 *
 *   Raymond Toy	toy@soho.crd.ge.com
 *	Modified the eepic.trm file to use PSTricks macros instead.
 *
 *	20 Mar 93:
 *		Utilized many suggestions from Gisli Ottarsson
 *		(gisli@liapunov.eecs.umich.edu) to create a new version.
 *		Should also work with TeX as well as LaTeX.
 *
 *   Bastian Maerkisch
 *
 * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
 *
 */

/*
 *  This file contains the PSTricks terminal driver, intended for use with the
 *  pstricks.sty macro package for LaTeX. This is an alternative to the
 *  eepic and latex driver. You need pstricks.sty, and, of course, a printer
 *  that understands PostScript.  Ghostscript understands Postscript too.
 *
 *  PSTricks is available at
 *     http://tug.org/PSTricks/
 *  This driver definitely does not come close to using the full capability
 *  of the PSTricks package.
 */
/*
 * adapted to the new terminal layout by Stefan Bodewig (Dec. 1995)
 *
 * adapted to support pm3d by Tim Piessens and Petr Mikulik (Jan. 2003)
 *
 * remove "hacktext" option since this functionality is now provided by
 * the %H format. Add rotated text at arbitrary angles, full color and
 * version 5 linetype support, filled boxes, pattern fill, variable
 * point size and line width, point symbols in line with other terminals,
 * boxed text, more arrow features, standalone (LaTeX) mode (including
 * text encoding support), transparency.  (BM, March/April 2018)
 * compatibility with plain TeX, and pdflatex/lualatex. (BM, Feb 2022)
 *
 */

#include "driver.h"

#ifdef TERM_REGISTER
register_term(pstricks)
#endif

#ifdef TERM_PROTO
TERM_PUBLIC void PSTRICKS_options(void);
TERM_PUBLIC void PSTRICKS_init(void);
TERM_PUBLIC void PSTRICKS_graphics(void);
TERM_PUBLIC void PSTRICKS_text(void);
TERM_PUBLIC void PSTRICKS_linetype(int linetype);
TERM_PUBLIC void PSTRICKS_move(unsigned int x, unsigned int y);
TERM_PUBLIC void PSTRICKS_point(unsigned int x, unsigned int y, int number);
TERM_PUBLIC void PSTRICKS_vector(unsigned int ux, unsigned int uy);
TERM_PUBLIC void PSTRICKS_arrow(unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head);
TERM_PUBLIC void PSTRICKS_pointsize(double pointsize);
TERM_PUBLIC void PSTRICKS_put_text(unsigned int x, unsigned int y, const char str[]);
TERM_PUBLIC int PSTRICKS_justify_text(enum JUSTIFY mode);
TERM_PUBLIC int PSTRICKS_text_angle(float ang);
TERM_PUBLIC void PSTRICKS_reset(void);
TERM_PUBLIC void PSTRICKS_linewidth(double linewidth);
TERM_PUBLIC int PSTRICKS_make_palette(t_sm_palette *);
TERM_PUBLIC void PSTRICKS_set_color(t_colorspec *);
TERM_PUBLIC void PSTRICKS_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height);
TERM_PUBLIC void PSTRICKS_filled_polygon(int, gpiPoint *);
TERM_PUBLIC void PSTRICKS_dashtype(int type, t_dashtype *custom_dash_pattern);
TERM_PUBLIC void PSTRICKS_boxed_text(unsigned int x, unsigned int y, int option);

#define PSTRICKS_XMAX 10000.0
#define PSTRICKS_YMAX 10000.0

#define PSTRICKS_HTIC	150
#define PSTRICKS_VTIC	150
#define PSTRICKS_HCHAR	160
#define PSTRICKS_VCHAR	250

#endif /* TERM_PROTO */

#ifndef TERM_PROTO_ONLY
#ifdef TERM_BODY

/* terminate any line in progress */
static void PSTRICKS_endline(void);

/* coordinate mapping functions */
static inline double PSTRICKS_map_x(int x);
static inline double PSTRICKS_map_y(int y);

/* apply line color */
static void PSTRICKS_save_color(const char * color);
static void PSTRICKS_apply_linecolor(void);

/* mode */
static TBOOLEAN PST_standalone = FALSE;
static TBOOLEAN PST_pdftricks2 = FALSE;

/* plot size */
static TBOOLEAN PST_unit_plot = FALSE;	/* Unit-sized plot off */
static size_units PSTRICKS_explicit_units = INCHES;
static float PSTRICKS_size_x = 5.f;
static float PSTRICKS_size_y = 3.f;

static float PSTRICKS_posx;
static float PSTRICKS_posy;


/* TEXT */
static TBOOLEAN PST_colortext = FALSE;
static enum JUSTIFY PSTRICKS_justify = LEFT;
static int PSTRICKS_angle = 0;

/* if 1 below, then the file size is shorter thanks to a macro for polygon */
/* FIXME: This feature is broken, deactivate for now */
//#define PSTRICKS_SHORTER_FILE 1

static int PSTRICKS_color_type = TC_DEFAULT;
static int PSTRICKS_color = 0;
static char PSTRICKS_color_str[24] = "";
static TBOOLEAN PSTRICKS_palette_set = FALSE;
static int PSTRICKS_palette_size = 128;
static rgb_color PSTRICKS_rgbcolor;
static double PSTRICKS_alpha = 1.;
static double PSTRICKS_alpha_old = 1.;
static TBOOLEAN PSTRICKS_have_bg;
static rgb_color PSTRICKS_background = { 1., 1., 1. };

/* POINTS */
#define	PSTRICKS_TINY_DOT	0.00025		/* A tiny dot */
static double PST_pointsize;
static double PSTRICKS_ps = 1.;
static const char *PSTRICKS_points[] = {
    "\\PST@Plus",
    "\\PST@Cross",
    "\\PST@Star",
    "\\PST@Square",
    "\\PST@Fillsquare",
    "\\PST@Circle",
    "\\PST@Fillcircle",
    "\\PST@Triangle",
    "\\PST@Filltriangle",
    "\\PST@TriangleD",
    "\\PST@FilltriangleD",
    "\\PST@Diamond",
    "\\PST@Filldiamond",
    "\\PST@Pentagon",
    "\\PST@Fillpentagon"
};
#define PSTRICKS_POINT_TYPES (sizeof(PSTRICKS_points) / sizeof(char *))


/* LINES */
#define PSTRICKS_NUMLINES 6	/* number of linetypes below */
static const char *PSTRICKS_lines[] = {
    "\\PST@Border",
    "\\PST@Axes",
    "\\PST@Solid",
    "\\PST@Dashed",
    "\\PST@Dotted",
    "\\PST@LongDash"
};

#define PSTRICKS_NUMCOLORS 6
static const char *PSTRICKS_colors[] = {
    "red",
    "green",
    "blue",
    "magenta",
    "darkgray",
    "cyan",
    "yellow"
};

/* line caps and joins */
static TBOOLEAN PST_rounded = FALSE;

/* current line type */
static int PSTRICKS_type;

/* current line color */
static char PSTRICKS_old_linecolor[24] = "black";
/* new line color */
static char PSTRICKS_linecolor[24] = "black";

/* line width */
static double PSTRICKS_lw;
static double PSTRICKS_lw_scale = 1.;

/* are we in the middle of a line */
static TBOOLEAN PSTRICKS_inline = FALSE;

/* number of points in line so far */
static int PSTRICKS_linecount = 0;

/* max value for linecount */
#define PSTRICKS_LINEMAX 100


/* ARROWS */
static TBOOLEAN PST_psarrows = TRUE;
static double PSTRICKS_arrowwidth = -1.;
static double PSTRICKS_arrowlength = -1.;
static double PSTRICKS_arrowinset = -1.;


/* FILL PATTERN */
static const char * PSTRICKS_patterns[] = {
    "solid",
    "crosshatch%s", "crosshatch%s,hatchsep=2.5pt",
    "solid",
    "vlines%s", "hlines%s",
    "vlines%s,hatchsep=2.5pt", "hlines%s,hatchsep=2.5pt",
    "dots*", "penrose%s"
};
#define PSTRICKS_NUMPATTERN (sizeof(PSTRICKS_patterns) / sizeof(char *))


/*  BOXED TEXT */
static TBOOLEAN PSTRICKS_in_textbox = FALSE;
static TBOOLEAN PSTRICKS_textbox_fill;
static TBOOLEAN PSTRICKS_textbox_frame;
static char * PSTRICKS_textbox_text  = NULL;
static double PSTRICKS_textbox_x;
static double PSTRICKS_textbox_y;
static char * PSTRICKS_textbox_fillcolor;
static double PSTRICKS_textbox_sep;

/*
 * Handle options
 */

/* option names */
enum PSTRICKS_id { PSTRICKS_DEFAULTOPTIONS,
	PSTRICKS_SIZE,
	PSTRICKS_UNIT, PSTRICKS_NOUNIT,
	PSTRICKS_STANDALONE, PSTRICKS_INPUT,
	PSTRICKS_PSTRICKS, PSTRICKS_PDFTRICKS2,
	PSTRICKS_BLACKTEXT, PSTRICKS_COLORTEXT,
	PSTRICKS_ROUNDED, PSTRICKS_BUTT,
	PSTRICKS_LINEWIDTH, PSTRICKS_POINTSCALE,
	PSTRICKS_PSARROWS, PSTRICKS_GPARROWS,
	PSTRICKS_BACKGROUND,
	PSTRICKS_OTHER };

static struct gen_table PSTRICKS_opts[] =
{
    { "def$ault", PSTRICKS_DEFAULTOPTIONS },
    { "size", PSTRICKS_SIZE },
    { "u$nit", PSTRICKS_UNIT },
    { "nou$nit", PSTRICKS_NOUNIT },
    { "stand$alone", PSTRICKS_STANDALONE },
    { "inp$ut", PSTRICKS_INPUT },
    { "b$lacktext", PSTRICKS_BLACKTEXT },
    { "colort$ext", PSTRICKS_COLORTEXT },
    { "colourt$ext", PSTRICKS_COLORTEXT },
    { "round$ed", PSTRICKS_ROUNDED },
    { "butt", PSTRICKS_BUTT },
    { "backg$round", PSTRICKS_BACKGROUND },
    { "lw", PSTRICKS_LINEWIDTH },
    { "linew$idth", PSTRICKS_LINEWIDTH },
    { "points$cale", PSTRICKS_POINTSCALE },
    { "ps", PSTRICKS_POINTSCALE },
    { "psarrows", PSTRICKS_PSARROWS },
    { "gparrows", PSTRICKS_GPARROWS },
    { "pst$ricks", PSTRICKS_PSTRICKS },
    { "pdf$tricks2", PSTRICKS_PDFTRICKS2 },
    { NULL, PSTRICKS_OTHER }
};


TERM_PUBLIC void
PSTRICKS_options()
{
    char size_str[80] = "";

    while (!END_OF_COMMAND) {
	switch ((enum PSTRICKS_id) lookup_table(&PSTRICKS_opts[0], c_token)) {
	case PSTRICKS_DEFAULTOPTIONS:
	    PST_unit_plot = FALSE;
	    PST_standalone = FALSE;
	    PST_pdftricks2 = FALSE;
	    PSTRICKS_size_x = 5.;
	    PSTRICKS_size_y = 3.;
	    break;
	case PSTRICKS_UNIT:
	    PST_unit_plot = TRUE;
	    PSTRICKS_size_x = 5.;
	    PSTRICKS_size_y = 5.;
	    term->xmax = PSTRICKS_XMAX;
	    term->ymax = PSTRICKS_YMAX;
	    term->v_char = PSTRICKS_VCHAR * 5. / 3.;
	    term->v_tic = PSTRICKS_VTIC * 5. / 3.;
	    c_token++;
	    break;
	case PSTRICKS_NOUNIT:
	    PST_unit_plot = FALSE;
	    PSTRICKS_size_x = 5.;
	    PSTRICKS_size_y = 3.;
	    term->xmax = PSTRICKS_size_x * PSTRICKS_XMAX / 5.;
	    term->ymax = PSTRICKS_size_y * PSTRICKS_YMAX / 5.;
	    term->v_char = PSTRICKS_VCHAR;
	    term->v_tic = PSTRICKS_VTIC;
	    c_token++;
	    break;
	case PSTRICKS_SIZE: {
	    float width, height;

	    c_token++;
	    PST_unit_plot = FALSE;
	    PSTRICKS_explicit_units = parse_term_size(&width, &height, INCHES);
	    PSTRICKS_size_x = width / gp_resolution;
	    PSTRICKS_size_y = height / gp_resolution;
	    term->xmax = PSTRICKS_size_x * PSTRICKS_XMAX / 5.;
	    term->ymax = PSTRICKS_size_y * PSTRICKS_YMAX / 5.;
	    term->v_char = PSTRICKS_VCHAR;
	    term->v_tic = PSTRICKS_VTIC;
	    break;
	}
	case PSTRICKS_STANDALONE:
	    PST_standalone = TRUE;
	    c_token++;
	    break;
	case PSTRICKS_INPUT:
	    PST_standalone = FALSE;
	    c_token++;
	    break;
	case PSTRICKS_COLORTEXT:
	    PST_colortext = TRUE;
	    c_token++;
	    break;
	case PSTRICKS_BLACKTEXT:
	    PST_colortext = FALSE;
	    c_token++;
	    break;
	case PSTRICKS_BUTT:
	    PST_rounded = FALSE;
	    c_token++;
	    break;
	case PSTRICKS_ROUNDED:
	    PST_rounded = TRUE;
	    c_token++;
	    break;
	case PSTRICKS_LINEWIDTH:
	    c_token++;
	    PSTRICKS_lw_scale = real_expression();
	    if (PSTRICKS_lw_scale < 0.0)
		PSTRICKS_lw_scale = 1.0;
	    break;
	case PSTRICKS_POINTSCALE:
	    c_token++;
	    PSTRICKS_ps = real_expression();
	    if (PSTRICKS_ps < 0.0)
		PSTRICKS_ps = 1.0;
	    break;
	case PSTRICKS_BACKGROUND: {
	    int background;

	    c_token++;
	    background = parse_color_name();
	    PSTRICKS_background.r = (double)((background >> 16) & 0xff) / 255.;
	    PSTRICKS_background.g = (double)((background >>  8) & 0xff) / 255.;
	    PSTRICKS_background.b = (double)( background        & 0xff) / 255.;
	    break;
	}
	case PSTRICKS_GPARROWS:
	    c_token++;
	    PST_psarrows = FALSE;
	    break;
	case PSTRICKS_PSARROWS:
	    c_token++;
	    PST_psarrows = TRUE;
	    break;
	case PSTRICKS_PSTRICKS:
	    c_token++;
	    PST_pdftricks2 = FALSE;
	    break;
	case PSTRICKS_PDFTRICKS2:
	    c_token++;
	    PST_pdftricks2 = TRUE;
	    break;
	default:
	    int_error(c_token, "Unknown terminal option");
	}
    }

    if (!PST_unit_plot) {
	if (PSTRICKS_explicit_units == INCHES)
	    snprintf(size_str, sizeof(size_str), "size %.2fin, %.2fin", PSTRICKS_size_x, PSTRICKS_size_y);
	else if (PSTRICKS_explicit_units == CM)
	    snprintf(size_str, sizeof(size_str), "size %.2fcm, %.2fcm", PSTRICKS_size_x * 2.54, PSTRICKS_size_y * 2.54);
    }

    // update terminal option string
    snprintf(term_options, MAX_LINE_LEN + 1,
	"%s %s linewidth %.1f pointscale %.1f %s " \
	"background \"#%02x%02x%02x\" %sarrows %s %s",
	PST_unit_plot ? "unit" : size_str,
	PST_rounded ? "rounded" : "butt",
	PSTRICKS_lw_scale, PSTRICKS_ps,
	PST_colortext ? "colortext" : "blacktext",
	(int) floor(PSTRICKS_background.r * 255 + 0.5),
	(int) floor(PSTRICKS_background.g * 255 + 0.5),
	(int) floor(PSTRICKS_background.b * 255 + 0.5),
	PST_psarrows ? "ps" : "gp",
	PST_standalone ? "standalone" : "input",
	PST_pdftricks2 ? "pdftricks2" : "pstricks");
}


TERM_PUBLIC void
PSTRICKS_init()
{
    fseek(gpoutfile, 0, SEEK_SET);

    if (PST_standalone) {
        const char * inputenc = latex_input_encoding(encoding);

	/* multiple standalone graphs */
	fputs("\\documentclass[a4paper]{article}\n"
	      "\\usepackage[T1]{fontenc}\n",
	      gpoutfile);
	if (PST_pdftricks2)
	    fputs("\\usepackage{pdftricks2}\n", gpoutfile);
	else
	    fputs("\\usepackage{pstricks}\n", gpoutfile);

	if (inputenc != NULL) {
	    if (encoding == S_ENC_UTF8)
		fputs("\\usepackage{pifont}\n"
		      "\\usepackage[postscript,warnunknown]{ucs}\n",
		      gpoutfile);
	    fprintf(gpoutfile,
		    "\\usepackage[%s]{inputenc}\n",
		    inputenc);
	}

	fputs("\\begin{document}\n",
	      gpoutfile);
    }

    fputs("% GNUPLOT: LaTeX picture using PSTRICKS macros\n", gpoutfile);
}


TERM_PUBLIC void
PSTRICKS_graphics()
{
    char background[80] = "";

    if (PST_standalone) {
	fputs("\\begin{figure}\n", gpoutfile);
    }

    if (PST_pdftricks2)
	fputs("\\begin{configpsblock}\n", gpoutfile);

    fputs("\
% Define new PST objects, if not already defined\n\
\\ifx\\PSTloaded\\undefined\n\
\\def\\PSTloaded{t}\n\
\\psset{arrowsize=.01 3.2 1.4 .3}\n\
\\psset{dotsize=0.15}\n\
\\catcode`@=11\n\n", gpoutfile);

    /* Define line type objects */
    fputs("\
\\newpsobject{PST@Border}{psline}{linestyle=solid}\n\
\\newpsobject{PST@Axes}{psline}{linestyle=dotted,dotsep=.004}\n\
\\newpsobject{PST@Solid}{psline}{linestyle=solid}\n\
\\newpsobject{PST@Dashed}{psline}{linestyle=dashed,dash=.01 .01}\n\
\\newpsobject{PST@Dotted}{psline}{linestyle=dotted,dotsep=.008}\n\
\\newpsobject{PST@LongDash}{psline}{linestyle=dashed,dash=.02 .01}\n", gpoutfile);

    /* Define point objects */
    fputs("\
\\newpsobject{PST@Plus}{psdot}{linewidth=.001,linestyle=solid,dotstyle=+}\n\
\\newpsobject{PST@Cross}{psdot}{linewidth=.001,linestyle=solid,dotstyle=+,dotangle=45}\n\
\\newpsobject{PST@Star}{psdot}{linewidth=.001,linestyle=solid,dotstyle=*}\n\
\\newpsobject{PST@Square}{psdot}{linewidth=.001,linestyle=solid,dotstyle=square}\n\
\\newpsobject{PST@Fillsquare}{psdot}{linewidth=.001,linestyle=solid,dotstyle=square*}\n\
\\newpsobject{PST@Circle}{psdot}{linewidth=.001,linestyle=solid,dotstyle=o}\n\
\\newpsobject{PST@Fillcircle}{psdot}{linewidth=.001,linestyle=solid,dotstyle=*}\n\
\\newpsobject{PST@Triangle}{psdot}{linewidth=.001,linestyle=solid,dotstyle=triangle}\n\
\\newpsobject{PST@Filltriangle}{psdot}{linewidth=.001,linestyle=solid,dotstyle=triangle*}\n\
\\newpsobject{PST@TriangleD}{psdot}{linewidth=.001,linestyle=solid,dotstyle=triangle,dotangle=180}\n\
\\newpsobject{PST@FilltriangleD}{psdot}{linewidth=.001,linestyle=solid,dotstyle=triangle*,dotangle=180}\n\
\\newpsobject{PST@Diamond}{psdot}{linewidth=.001,linestyle=solid,dotstyle=square,dotangle=45}\n\
\\newpsobject{PST@Filldiamond}{psdot}{linewidth=.001,linestyle=solid,dotstyle=square*,dotangle=45}\n\
\\newpsobject{PST@Pentagon}{psdot}{linewidth=.001,linestyle=solid,dotstyle=pentagon}\n\
\\newpsobject{PST@Fillpentagon}{psdot}{linewidth=.001,linestyle=solid,dotstyle=pentagon*}\n", gpoutfile);

    /* Define arrow object */
    fputs("\
\\newpsobject{PST@Arrow}{psline}{linestyle=solid}\n\
\\catcode`@=12\n\n\
\\fi\n", gpoutfile);

    if (PST_pdftricks2)
	fputs("\\end{configpsblock}\n", gpoutfile);

    /* background color */
    PSTRICKS_have_bg = FALSE;
    if (PSTRICKS_background.r != 1. || PSTRICKS_background.g != 1. || PSTRICKS_background.b != 1.) {
	PSTRICKS_have_bg = TRUE;
	fprintf(gpoutfile, "\\newrgbcolor{PST@BGCOLOR}{%f %f %f}\n",
	    PSTRICKS_background.r, PSTRICKS_background.g, PSTRICKS_background.b);
	safe_strncpy(background, "[bgcolor=PST@BGCOLOR]", sizeof(background));
    }

    /* Set the scaled plot size, if it's not a unit plot */
    if (!PST_unit_plot) {
	// Choose 5in as unit for historical reasons only.
	fputs("\\psset{unit=5.0in}\n", gpoutfile);
	fprintf(gpoutfile,
	    PST_pdftricks2 ?
		"\\begin{pspicture*}%s(%f,%f)(%f,%f)\n" :
		"\\pspicture%s(%f,%f)(%f,%f)\n",
	    background,
	    0., 0.,
	    PSTRICKS_size_x / 5., PSTRICKS_size_y / 5.
	);
	fputs("\
\\ifx\\nofigs\\undefined\n\
\\catcode`@=11\n\n",
	    gpoutfile
	);
    } else {
	fprintf(gpoutfile, "\
\\pspicture%s(%f,%f)(%f,%f)\n\
\\ifx\\nofigs\\undefined\n\
\\catcode`@=11\n\n",
	    background,
	    0., 0., 1., 1.
	);
    }
    PSTRICKS_posx = PSTRICKS_posy = 0;
    PSTRICKS_linetype(-1);
    PSTRICKS_palette_set = FALSE;    /* PM3D palette set? */
    /* Re-set point symbol size */
    fputs("\\psset{dotscale=1}\n", gpoutfile);
    PST_pointsize = 1.;
    strcpy(PSTRICKS_old_linecolor, "black");
    strcpy(PSTRICKS_linecolor, "black");
    PSTRICKS_lw = 1;
    PSTRICKS_arrowwidth = PSTRICKS_arrowlength = PSTRICKS_arrowinset = -1;
    fprintf(gpoutfile, "\\psset{linecap=%d,linejoin=%d}\n", PST_rounded ? 1 : 0, PST_rounded ? 1 : 0);
}


TERM_PUBLIC void
PSTRICKS_text()
{
    PSTRICKS_endline();
    fputs("\
\\catcode`@=12\n\
\\fi\n", gpoutfile);
    fputs(PST_pdftricks2 ?
	"\\end{pspicture*}\n" : "\\endpspicture\n",
	gpoutfile);

    if (PST_standalone) {
	fputs("\\end{figure}\n", gpoutfile);
    }
}


/* coordinate mapping functions */
static inline double
PSTRICKS_map_x(int x)
{
    return x / PSTRICKS_XMAX;
}


static inline double
PSTRICKS_map_y(int y)
{
    return y / PSTRICKS_YMAX;
}


TERM_PUBLIC void
PSTRICKS_linetype(int linetype)
{
    PSTRICKS_endline();

    /* all lines except for axis default to solid */
    if (linetype == LT_AXIS)
	PSTRICKS_type = -1;
    else
	PSTRICKS_type = 0;

    /* negative line types are all black */
    if (linetype < 0) {
	PSTRICKS_color_type = TC_DEFAULT;
	PSTRICKS_save_color("black");
    } else {
	PSTRICKS_color_type = TC_LT;
	PSTRICKS_color = linetype % PSTRICKS_NUMCOLORS;
	PSTRICKS_save_color(PSTRICKS_colors[PSTRICKS_color]);
    }
}


TERM_PUBLIC void
PSTRICKS_dashtype(int dt, t_dashtype *custom_dash_pattern)
{
    PSTRICKS_endline();

    if (dt >= 0) {
	int linetype = dt;
	if (linetype >= PSTRICKS_NUMLINES + LT_BLACK)
	    linetype %= (PSTRICKS_NUMLINES + LT_BLACK);
	if (linetype < LT_BLACK)
	    linetype = LT_BLACK;
	PSTRICKS_type = linetype;
    } else if (dt == DASHTYPE_SOLID) {
	PSTRICKS_type = 0;
    } else if (dt == DASHTYPE_AXIS) {
	PSTRICKS_type = -1;
    } else if (dt == DASHTYPE_CUSTOM) {
	/* not supported */
    }
}


TERM_PUBLIC void
PSTRICKS_move(unsigned int x, unsigned int y)
{
    PSTRICKS_endline();

    PSTRICKS_posx = PSTRICKS_map_x(x);
    PSTRICKS_posy = PSTRICKS_map_y(y);
}


TERM_PUBLIC void
PSTRICKS_point(unsigned int x, unsigned int y, int number)
{
    PSTRICKS_move(x, y);

    /* Print the character defined by 'number'; number < 0 means
       to use a dot, otherwise one of the defined points. */

    if (PST_pointsize <= 0.)
	return;

    PSTRICKS_apply_linecolor();

    if (number < 0) {
	fprintf(gpoutfile, "\\qdisk(%.4f,%.4f){%.4f}\n",
		PSTRICKS_map_x(x),
		PSTRICKS_map_y(y),
		PSTRICKS_TINY_DOT);
    } else {
	fprintf(gpoutfile, "%s(%.4f,%.4f)\n",
		PSTRICKS_points[number % PSTRICKS_POINT_TYPES],
		PSTRICKS_map_x(x),
		PSTRICKS_map_y(y));
    }
}


TERM_PUBLIC void
PSTRICKS_vector(unsigned ux, unsigned uy)
{
    if (!PSTRICKS_inline) {
	PSTRICKS_inline = TRUE;

	/* Start a new line. This depends on line type */
	PSTRICKS_apply_linecolor();
	fprintf(gpoutfile, "%s(%.4f,%.4f)",
		PSTRICKS_lines[PSTRICKS_type + 2],
		PSTRICKS_posx, PSTRICKS_posy);
	PSTRICKS_linecount = 1;
    } else {
	/*
	 * Even though we are in middle of a path,
	 * we may want to start a new path command.
	 * If they are too long then latex will choke.
	 */
	if (PSTRICKS_linecount++ >= PSTRICKS_LINEMAX) {
	    putc('\n', gpoutfile);
	    fprintf(gpoutfile, "%s(%.4f,%.4f)",
		    PSTRICKS_lines[PSTRICKS_type + 2],
		    PSTRICKS_posx, PSTRICKS_posy);
	    PSTRICKS_linecount = 1;
	}
    }
    if (PSTRICKS_linecount % 8 == 0)
	putc('\n', gpoutfile);
    PSTRICKS_posx = PSTRICKS_map_x(ux);
    PSTRICKS_posy = PSTRICKS_map_y(uy);
    fprintf(gpoutfile, "(%.4f,%.4f)", PSTRICKS_posx, PSTRICKS_posy);
}


static void
PSTRICKS_endline()
{
    if (PSTRICKS_inline) {
	if (PSTRICKS_linecount % 8 != 0)
	    putc('\n', gpoutfile);
	putc('\n', gpoutfile);
	PSTRICKS_inline = FALSE;
    }
}


TERM_PUBLIC void
PSTRICKS_arrow(
    unsigned int sx, unsigned int sy,
    unsigned int ex, unsigned int ey,
    int head)
{
    const char * head_str = "";
    double width, length, inset = 0.;

    /* Note:  we cannot handle curr_arrow_headfilled, HEADS_ONLY, and SHAFT_ONLY */
    PSTRICKS_endline();
    PSTRICKS_apply_linecolor();

    if (!PST_psarrows) {
	do_arrow(sx, sy, ex, ey, head);
	return;
    }

    if (curr_arrow_headlength <= 0) {
	double def_length = PSTRICKS_HTIC;
	width = 2 * def_length * sin(DEG2RAD * 15);
	length = def_length * cos(DEG2RAD * 15);
	inset = 0;
    } else {
	width = 2 * curr_arrow_headlength * sin(DEG2RAD * curr_arrow_headangle);
	length = curr_arrow_headlength * cos(DEG2RAD * curr_arrow_headangle);

	if (curr_arrow_headbackangle != 90)
	    inset = width / 2. / tan(DEG2RAD * curr_arrow_headbackangle);
    }

    if (curr_arrow_headangle != 90 || curr_arrow_headlength <= 0) {
	if ((PSTRICKS_map_x(width) / PSTRICKS_lw) != PSTRICKS_arrowwidth) {
	    PSTRICKS_arrowwidth = PSTRICKS_map_x(width) / PSTRICKS_lw;
	    fprintf(gpoutfile, "\\psset{arrowsize=0 %.3f}\n", PSTRICKS_arrowwidth);
	}
	if ((width != 0.) && ((length / width) != PSTRICKS_arrowlength)) {
	    PSTRICKS_arrowlength = length / width;
	    fprintf(gpoutfile, "\\psset{arrowlength=%.2f}\n", PSTRICKS_arrowlength);
	}
	if ((width != 0.) && ((inset / width) != PSTRICKS_arrowinset)) {
	    PSTRICKS_arrowinset = inset / width;
	    fprintf(gpoutfile, "\\psset{arrowinset=%.2f}\n", PSTRICKS_arrowinset);
	} else if ((width == 0.) && (PSTRICKS_arrowinset != 0.)) {
	    PSTRICKS_arrowinset = 0.;
	    fputs("\\psset{arrowinset=0}\n", gpoutfile);
	}
	/*
	fprintf(gpoutfile, "%% %.3f %.1f %.1f\n",
	    curr_arrow_headbackangle / PSTRICKS_XMAX,
	    curr_arrow_headangle,
	    curr_arrow_headbackangle);
	*/

	if (width == 0.)
	    head &= ~BOTH_HEADS;

	if ((head & BOTH_HEADS) == BOTH_HEADS)
	    head_str = "{<->}";
	else if (head & END_HEAD)
	    head_str = "{->}";
	else if (head & BACKHEAD)
	    head_str = "{<-}";
    } else {
	if ((PSTRICKS_map_x(width) / PSTRICKS_lw) != PSTRICKS_arrowwidth) {
	    PSTRICKS_arrowwidth = PSTRICKS_map_x(width) / PSTRICKS_lw;
	    fprintf(gpoutfile, "\\psset{tbarsize=0 %.3f}\n", PSTRICKS_arrowwidth);
	}
	if ((head & BOTH_HEADS) == BOTH_HEADS)
	    head_str = "{|-|}";
	else if (head & END_HEAD)
	    head_str = "{-|}";
	else if (head & BACKHEAD)
	    head_str = "{|-}";
    }

    fprintf(gpoutfile, "%s%s(%.4f,%.4f)(%.4f,%.4f)\n",
	    PSTRICKS_lines[PSTRICKS_type + 2],
	    head_str,
	    PSTRICKS_map_x(sx), PSTRICKS_map_y(sy),
	    PSTRICKS_map_x(ex), PSTRICKS_map_y(ey));

    PSTRICKS_posx = PSTRICKS_map_x(ex);
    PSTRICKS_posy = PSTRICKS_map_y(ey);
}


TERM_PUBLIC void
PSTRICKS_pointsize(double pointsize)
{
    pointsize *= PSTRICKS_ps;
    if (PST_pointsize != pointsize) {
	PSTRICKS_endline();
	if (pointsize != 0.)
	    fprintf(gpoutfile, "\\psset{dotscale=%f}\n", pointsize);
	PST_pointsize = pointsize;
    }
}


TERM_PUBLIC void
PSTRICKS_put_text(unsigned int x, unsigned int y, const char str[])
{
    PSTRICKS_endline();

    if (PSTRICKS_in_textbox && (PSTRICKS_textbox_text == NULL)) {
	PSTRICKS_textbox_text = strdup(str);
	return;
    }

    /* Skip this if the string is empty */
    if (strlen(str) > 0) {
	fputs("\\rput", gpoutfile);

	/* Set justification */
	switch (PSTRICKS_justify) {
	case LEFT:
	    fputs("[l]", gpoutfile);
	    break;
	case CENTRE:
	    break;
	case RIGHT:
	    fputs("[r]", gpoutfile);
	    break;
	}

	/* Set text angle */
	switch (PSTRICKS_angle) {
	case 0:
	    break;
	case 90:
	    fputs("{L}", gpoutfile);
	    break;
	default:
	    fprintf(gpoutfile, "{%i}", PSTRICKS_angle);
	    break;
	}

	/* Set reference position and text */
	fprintf(gpoutfile, "(%.4f,%.4f)",
		PSTRICKS_map_x(x),
		PSTRICKS_map_y(y));
	if (!PST_colortext || (strcmp(PSTRICKS_linecolor, "black") == 0))
	    fprintf(gpoutfile, "{%s}\n", str);
	else
	    fprintf(gpoutfile, "{\\%s %s}\n", PSTRICKS_linecolor, str);
    }
}


TERM_PUBLIC int
PSTRICKS_justify_text(enum JUSTIFY mode)
{
    PSTRICKS_justify = mode;
    return TRUE;
}


TERM_PUBLIC int
PSTRICKS_text_angle(float ang)
{
    PSTRICKS_angle = ang;
    while (PSTRICKS_angle < 0)
	PSTRICKS_angle += 360;
    while (PSTRICKS_angle > 360)
	PSTRICKS_angle -= 360;
    return TRUE;
}


TERM_PUBLIC void
PSTRICKS_reset()
{
    PSTRICKS_endline();
    PSTRICKS_posx = PSTRICKS_posy = 0;

    if (PST_standalone)
	fputs("\\end{document}\n", gpoutfile);
}


TERM_PUBLIC void
PSTRICKS_linewidth(double linewidth)
{
    linewidth *= PSTRICKS_lw_scale;
    if (linewidth * 0.0015 != PSTRICKS_lw) {
	PSTRICKS_endline();
	PSTRICKS_lw = linewidth * 0.0015;
	fprintf(gpoutfile, "\\psset{linewidth=%.4f}\n", PSTRICKS_lw);
    }
}


TERM_PUBLIC int
PSTRICKS_make_palette(t_sm_palette *palette)
{
    /* Query to determine palette size */
    if (palette == NULL) {
	return PSTRICKS_palette_size;
    }

    PSTRICKS_endline();

    if (PSTRICKS_palette_set == FALSE) {
	int i;

	/* Create new palette */
	PSTRICKS_palette_set = TRUE;
	if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY) {
	    /* Grey palette */
	    for (i = 0; i < sm_palette.colors; i++) {
		double g = i * 1.0 / (sm_palette.colors - 1);
		g = 1e-3 * (int)(g * 1000); /* round to 3 digits to use %g below */
		fprintf(gpoutfile, "\\newgray{PST@COLOR%d}{%g}\n", i, g);
	    }
	} else {
	    for (i = 0; i < sm_palette.colors; i++) {
		double r, g, b;

		/* round to 3 digits */
		r = 1e-3 * (int)(palette->color[i].r * 1000);
		g = 1e-3 * (int)(palette->color[i].g * 1000);
		b = 1e-3 * (int)(palette->color[i].b * 1000);
		fprintf(gpoutfile, "\\newrgbcolor{PST@COLOR%d}{%f %f %f}\n", i, r, g, b);
	    }
	}
    }
#ifdef PSTRICKS_SHORTER_FILE
    /* use the following macro to shorten the file size */
    fputs("\\def\\polypmIIId#1{\\pspolygon[linestyle=none,fillstyle=solid,fillcolor=PST@COLOR#1]}\n\n", gpoutfile);
#endif
    return 0;
}


static void
PSTRICKS_save_color(const char * color)
{
    if (color != NULL)
	strcpy(PSTRICKS_linecolor, color);
}


static void
PSTRICKS_apply_linecolor(void)
{
    if (strcmp(PSTRICKS_linecolor, PSTRICKS_old_linecolor) != 0) {
	PSTRICKS_endline();
	strcpy(PSTRICKS_old_linecolor, PSTRICKS_linecolor);
	fprintf(gpoutfile, "\\psset{linecolor=%s}\n", PSTRICKS_linecolor);
    }
    if (PSTRICKS_alpha != PSTRICKS_alpha_old) {
	/* We set the opacity of lines and fills. Required for transparent symbols. */
	fprintf(gpoutfile, "\\psset{strokeopacity=%0.2f,opacity=%0.2f}\n", PSTRICKS_alpha, PSTRICKS_alpha);
	PSTRICKS_alpha_old = PSTRICKS_alpha;
    }
}


TERM_PUBLIC void
PSTRICKS_set_color(t_colorspec *colorspec)
{
    int new_color;
    double gray = colorspec->value;

    switch (colorspec->type) {
    case TC_FRAC:
	PSTRICKS_color_type = colorspec->type;
	if (CHECK_SMPAL_IS_DISCRETE_GRADIENT) {
	    new_color = index_from_gray(gray);
        } else {
	    if (sm_palette.use_maxcolors != 0)
	        gray = quantize_gray(gray);
	    new_color = (gray <= 0) ? 0 : (gray >= 1) ? sm_palette.colors - 1 : (int)(gray * sm_palette.colors);
	    if (new_color >= PSTRICKS_palette_size)
	        new_color = PSTRICKS_palette_size - 1;
        }
	if (PSTRICKS_palette_set == FALSE) {
	    fputs("pstricks: Palette used before set!\n", stderr);
	    fputs("% ERROR: Palette used before set!\n", gpoutfile);
	}
	PSTRICKS_color = new_color;
	snprintf(PSTRICKS_color_str, sizeof(PSTRICKS_color_str), "PST@COLOR%d", new_color);
	PSTRICKS_save_color(PSTRICKS_color_str);
	PSTRICKS_alpha = 1.;
	break;
    case TC_RGB: {
	int red, green, blue;
	double r, g, b, alpha;

	red   = (colorspec->lt >> 16) & 0xff;
	green = (colorspec->lt >>  8) & 0xff;
	blue  = (colorspec->lt      ) & 0xff;
	alpha = (double) (255 - ((colorspec->lt >> 24) & 0xff)) / 255;
	/* round to 3 digits */
	r = 1e-3 * (int)(red   / 255. * 1000);
	g = 1e-3 * (int)(green / 255. * 1000);
	b = 1e-3 * (int)(blue  / 255. * 1000);
	if ((PSTRICKS_color_type != TC_RGB) ||
	    (PSTRICKS_rgbcolor.r != r) ||
	    (PSTRICKS_rgbcolor.g != g) ||
	    (PSTRICKS_rgbcolor.b != b)) {
	    PSTRICKS_endline();
	    fprintf(gpoutfile, "\\newrgbcolor{c}{%g %g %g}\n",  r, g, b);
	    PSTRICKS_old_linecolor[0] = 0; /* invalidate old color */
	    strcpy(PSTRICKS_linecolor, "c");
	    PSTRICKS_color_type = colorspec->type;
	    PSTRICKS_rgbcolor.r = r;
	    PSTRICKS_rgbcolor.g = g;
	    PSTRICKS_rgbcolor.b = b;
	}
	PSTRICKS_alpha = alpha;
	break;
    }
    case TC_LT:
	if (colorspec->lt < 0) {
	    PSTRICKS_color_type = TC_DEFAULT;
	    PSTRICKS_save_color("black");
	} else {
	    PSTRICKS_color_type = TC_LT;
	    PSTRICKS_color = colorspec->lt % PSTRICKS_NUMCOLORS;
	    PSTRICKS_save_color(PSTRICKS_colors[PSTRICKS_color]);
	}
	PSTRICKS_alpha = 1.;
	break;
    default:
	break;
    }
}


TERM_PUBLIC void
PSTRICKS_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)
{
    int pattern = style >> 4;
    int frac = style >> 4;
    const char * stylestr = "solid";
    const char * colorstr = "fillcolor";
    char patfill[80];
    char opacity[80] = "";
    char fraction[80] = "";

    PSTRICKS_endline();

    switch (style & 0x0f) {
    case FS_SOLID:
	// color already set
	if (frac != 100)
	    snprintf(fraction, sizeof(fraction), "!%d", frac);
	if (PSTRICKS_alpha != 1.)
	    snprintf(opacity, sizeof(opacity), ",opacity=%0.2f", PSTRICKS_alpha);
	break;
    case FS_TRANSPARENT_SOLID:
	// color already set
	if (frac != 100)
	    snprintf(opacity, sizeof(opacity), ",opacity=%0.2f", (double) frac / 100.);
	break;
    case FS_PATTERN:
    case FS_TRANSPARENT_PATTERN:
	stylestr = (char *) PSTRICKS_patterns[pattern % PSTRICKS_NUMPATTERN];
	if (pattern != 0)
	    colorstr = "hatchcolor";
	snprintf(patfill, sizeof(patfill), stylestr, (style & 0x0f) == FS_PATTERN ? "*" : "");
	if ((style & 0x0f) == FS_PATTERN && PSTRICKS_have_bg)
	    strncat(patfill, ",fillcolor=PST@BGCOLOR", sizeof(patfill)-strlen(patfill)-1);
	stylestr = patfill;
	break;
    case FS_EMPTY:
	break;
    case FS_DEFAULT:
    default:
	break;
    }

    fprintf(gpoutfile, "\\psframe[linestyle=none,fillstyle=%s", stylestr);
    if (PSTRICKS_color_type == TC_FRAC) {
#ifdef PSTRICKS_SHORTER_FILE
	fprintf(gpoutfile, "%s,%s=PST@COLOR%d%s]", opacity, colorstr, PSTRICKS_color, fraction);
#else
	fprintf(gpoutfile, "%s,%s=%s%s]", opacity, colorstr, PSTRICKS_color_str, fraction);
#endif
    } else if (PSTRICKS_color_type == TC_RGB) {
	fprintf(gpoutfile, "%s,%s=c%s]", opacity, colorstr, fraction);
    } else if (PSTRICKS_color_type == TC_LT) {
	fprintf(gpoutfile, "%s,%s=%s%s]", opacity, colorstr, PSTRICKS_colors[PSTRICKS_color], fraction);
    } else {  // e.g. TC_DEFAULT
	fprintf(gpoutfile, "%s]", opacity);
    }
    fprintf(gpoutfile, "(%.4g,%.4g)(%.4g,%.4g)\n",
	PSTRICKS_map_x(x1), PSTRICKS_map_y(y1),
	PSTRICKS_map_x(x1 + width), PSTRICKS_map_y(y1 + height));
}


TERM_PUBLIC void
PSTRICKS_filled_polygon(int points, gpiPoint *corners)
{
    int style = corners->style;
    int pattern = style >> 4;
    int frac = style >> 4;
    const char * stylestr = "solid";
    const char * colorstr = "fillcolor";
    char patfill[80];
    char opacity[80] = "";
    char fraction[80] = "";
    int i;

    PSTRICKS_endline();

    switch (style & 0x0f) {
    case FS_SOLID:
	// color already set
	if (frac != 100)
	    snprintf(fraction, sizeof(fraction), "!%d", frac);
	if (PSTRICKS_alpha != 1.)
	    snprintf(opacity, sizeof(opacity), ",opacity=%0.2f", PSTRICKS_alpha);
	break;
    case FS_TRANSPARENT_SOLID:
	// color already set
	if (frac != 100)
	    snprintf(opacity, sizeof(opacity), ",opacity=%0.2f", (double) frac / 100.);
	break;
    case FS_PATTERN:
    case FS_TRANSPARENT_PATTERN:
	stylestr = (char *) PSTRICKS_patterns[pattern % PSTRICKS_NUMPATTERN];
	if (pattern != 0)
	    colorstr = "hatchcolor";
	snprintf(patfill, sizeof(patfill), stylestr, (style & 0x0f) == FS_PATTERN ? "*" : "");
	if ((style & 0x0f) == FS_PATTERN && PSTRICKS_have_bg)
	    strncat(patfill, ",fillcolor=PST@BGCOLOR", sizeof(patfill)-strlen(patfill)-1);
	stylestr = patfill;
	break;
    case FS_EMPTY:
	break;
    case FS_DEFAULT:
    default:
	break;
    }

    if (PSTRICKS_color_type == TC_FRAC) {
#ifdef PSTRICKS_SHORTER_FILE
	/* using a macro for an abbreviation */
	fprintf(gpoutfile, "\\polypmIIId{%d}", PSTRICKS_color);
#else
	fprintf(gpoutfile, "\\pspolygon[linestyle=none,fillstyle=%s%s,%s=%s%s]", stylestr, opacity, colorstr, PSTRICKS_color_str, fraction);
#endif
    } else if (PSTRICKS_color_type == TC_RGB) {
	fprintf(gpoutfile, "\\pspolygon[linestyle=none,fillstyle=%s%s,%s=c%s]", stylestr, opacity, colorstr, fraction);
    } else if (PSTRICKS_color_type == TC_LT) {
	fprintf(gpoutfile, "\\pspolygon[linestyle=none,fillstyle=%s%s,%s=%s%s]", stylestr, opacity, colorstr, PSTRICKS_colors[PSTRICKS_color], fraction);
    } else {
	fprintf(gpoutfile, "\\pspolygon[linestyle=none,fillstyle=%s%s]", stylestr, opacity);
    }
    for (i = 0; i < points; i++) {
	if (i % 8 == 7) /* up to 8 corners per line */
	    fputs("\n", gpoutfile);
	fprintf(gpoutfile,"(%.4g,%.4g)", PSTRICKS_map_x(corners[i].x), PSTRICKS_map_y(corners[i].y));
    }
    /* make sure that polygons are closed - avoids spurious artifacts */
    if ((corners[0].x != corners[points - 1].x) || (corners[0].y != corners[points - 1].y))
	fprintf(gpoutfile,"(%.4g,%.4g)", PSTRICKS_map_x(corners[0].x), PSTRICKS_map_y(corners[0].y));
    fputs("\n\n", gpoutfile);
}


TERM_PUBLIC void
PSTRICKS_boxed_text(unsigned int x, unsigned int y, int option)
{
    switch (option) {
    case TEXTBOX_INIT:
	if (!PSTRICKS_in_textbox) {
	    /* ignore second init call */
	    PSTRICKS_in_textbox = TRUE;
	    PSTRICKS_textbox_x = PSTRICKS_map_x(x);
	    PSTRICKS_textbox_y = PSTRICKS_map_y(y);
	    PSTRICKS_textbox_fill = FALSE;
	    PSTRICKS_textbox_frame = FALSE;
	    PSTRICKS_textbox_text  = NULL;
	    PSTRICKS_textbox_fillcolor = NULL;
	}
	//printf("textbox init ");
	break;
    case TEXTBOX_OUTLINE:
	PSTRICKS_textbox_frame = TRUE;
	//printf(" outline ");
	break;
    case TEXTBOX_BACKGROUNDFILL:
	PSTRICKS_textbox_fill = TRUE;
	if (PSTRICKS_color_type == TC_DEFAULT)
	    PSTRICKS_textbox_fillcolor = strdup("white");
	else
	    PSTRICKS_textbox_fillcolor = strdup(PSTRICKS_linecolor);
	//printf(" border ");
	break;
    case TEXTBOX_MARGINS:
	PSTRICKS_textbox_sep = PSTRICKS_map_x(term->h_char * GPMAX(x, y) / 1000);
	break;
    case TEXTBOX_FINISH:
	//printf("... finish\n");
	PSTRICKS_in_textbox = FALSE;
	if (!PSTRICKS_textbox_text)
	    return;
	if (PSTRICKS_textbox_fill && PSTRICKS_textbox_frame) {
	    fprintf(gpoutfile,
		"\\rput(%.4f,%.4f){"
		    "\\psframebox[linecolor=%s,framesep=0]{"
			"\\psframebox*[fillcolor=%s,fillstyle=solid,framesep=%.4f]{%s}}}",
		PSTRICKS_textbox_x, PSTRICKS_textbox_y,
		PSTRICKS_linecolor, PSTRICKS_textbox_fillcolor,
		PSTRICKS_textbox_sep,
		PSTRICKS_textbox_text);
	} else if (PSTRICKS_textbox_frame) {
	    fprintf(gpoutfile,
		"\\rput(%.4f,%.4f){"
		    "\\psframebox[linecolor=black,framesep=%.4f]{%s}}",
		PSTRICKS_textbox_x, PSTRICKS_textbox_y,
		PSTRICKS_textbox_sep,
		PSTRICKS_textbox_text);
	} else {
	    fprintf(gpoutfile,
		"\\rput(%.4f,%.4f){"
		    "\\psframebox*[fillcolor=%s,fillstyle=solid,framesep=%.4f]{%s}}",
		PSTRICKS_textbox_x, PSTRICKS_textbox_y,
		PSTRICKS_textbox_fillcolor,
		PSTRICKS_textbox_sep,
		PSTRICKS_textbox_text);
	}
	free(PSTRICKS_textbox_text);
	if (PSTRICKS_textbox_fillcolor)
	    free(PSTRICKS_textbox_fillcolor);
	break;
    }
}

#endif /* TERM_BODY */


#ifdef TERM_TABLE
TERM_TABLE_START(pstricks_driver)
    "pstricks", "LaTeX picture environment with PSTricks macros",
    PSTRICKS_XMAX, PSTRICKS_YMAX * 3./5., PSTRICKS_VCHAR, PSTRICKS_HCHAR,
    PSTRICKS_VTIC, PSTRICKS_HTIC, PSTRICKS_options, PSTRICKS_init, PSTRICKS_reset,
    PSTRICKS_text, null_scale, PSTRICKS_graphics, PSTRICKS_move, PSTRICKS_vector,
    PSTRICKS_linetype, PSTRICKS_put_text, PSTRICKS_text_angle,
    PSTRICKS_justify_text, PSTRICKS_point, PSTRICKS_arrow, set_font_null, PSTRICKS_pointsize,
    TERM_BINARY | TERM_IS_LATEX | TERM_CAN_DASH | TERM_ALPHA_CHANNEL |
    TERM_LINEWIDTH | TERM_POINTSCALE,
    0 /*suspend*/, 0 /*resume*/,
    PSTRICKS_fillbox, PSTRICKS_linewidth,
#ifdef USE_MOUSE
    0, 0, 0, 0, 0,
#endif
    PSTRICKS_make_palette, 0, PSTRICKS_set_color, PSTRICKS_filled_polygon,
    0, /* image */
    0, 0, 0, /* enhanced text */
    0, /* layer */
    0, /* path */
    0.0, /* scale (unused) */
    0, /* hypertext */
    PSTRICKS_boxed_text,
    0,
    PSTRICKS_dashtype
TERM_TABLE_END(pstricks_driver)

#undef LAST_TERM
#define LAST_TERM pstricks_driver

#endif /* TERM_TABLE */
#endif /* TERM_PROTO_ONLY */


#ifdef TERM_HELP
START_HELP(pstricks)
"1 pstricks",
"?commands set terminal pstricks",
"?set terminal pstricks",
"?set term pstricks",
"?terminal pstricks",
"?term pstricks",
"?pstricks",
" The `pstricks` driver is intended for use with the \"pstricks.sty\" macro",
" package for TeX or LaTeX.",
" You need \"pstricks.sty\", and, of course, a printer that understands",
" PostScript, or a converter such as Ghostscript.",
"",
" PSTricks is available at",
"^ <a href=\"http://tug.org/PSTricks/\">",
"           http://tug.org/PSTricks/.",
"^ </a>",
" This driver definitely does not come close to using the full",
" capability of the PSTricks package.",
"",
" Syntax:",
"       set terminal pstricks",
"                      {unit | size <XX>{unit},<YY>{unit}}",
"                      {standalone | input}",
"                      {blacktext | colortext | colourtext}",
"                      {linewidth <lw>} {rounded | butt}",
"                      {pointscale <ps>}",
"                      {psarrows | gparrows}",
"                      {background <rgbcolor>}",
"                      {pstricks | pdftricks2}",
"",
" The `unit` option produces a plot with internal dimensions 1x1. The default",
" is a plot of `size 5in,3in`.",
"",
" `standalone` produces a LaTeX file with possibly multiple plots, ready",
" to be compiled.  The default is `input` to produce a TeX file which can",
" be included.",
"",
" `blacktext` forces all text to be written in black. `colortext` enables",
" colored text. The default is `blacktext`.",
"",
" `rounded` sets line caps and line joins to be rounded. `butt` sets butt",
" caps and mitered joins and is the default.",
"",
" `linewidth` and `pointscale` scale the width of lines and the size of point",
" symbols, respectively.",
"",
" `psarrows` draws `arrow`s using PSTricks commands which are shorter but do",
" not offer all options. `gparrows` selects drawing arrows using gnuplot's own",
" routine for full functionality instead.",
"",
" With the option `pdftricks2` you can create output for the `pdftricks2`",
" macro package, which can be used with pdflatex/lualatex. Otherwise, output",
" for the `pstricks` package with traditional tex/latex or xelatex is",
" produced.",
"",
" The old `hacktext` option has been replaced by the new default format (%h),",
" see `format specifiers`.",
"",
" Transparency requires support by Ghostscript or conversion to PDF."
END_HELP(pstricks)
#endif /* TERM_HELP */
